Skip to content

Implement SubBasis#61

Merged
blegat merged 16 commits into
mainfrom
mk/subbasis
Apr 29, 2025
Merged

Implement SubBasis#61
blegat merged 16 commits into
mainfrom
mk/subbasis

Conversation

@kalmarek

@kalmarek kalmarek commented Nov 7, 2024

Copy link
Copy Markdown
Collaborator

@codecov

codecov Bot commented Nov 7, 2024

Copy link
Copy Markdown

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 84.42%. Comparing base (a49b4ca) to head (1a2d366).
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #61      +/-   ##
==========================================
+ Coverage   83.90%   84.42%   +0.51%     
==========================================
  Files          15       15              
  Lines         845      873      +28     
==========================================
+ Hits          709      737      +28     
  Misses        136      136              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread src/bases_fixed.jl Outdated
k = findfirst(==(x), supp(b))
isnothing(k) && throw("x=$x is not supported on SubBasis")
@info T I
return convert(I, k)

@blegat blegat Nov 7, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be convert(I, b.parent_basis[b.supporting_elts[x]]) because we store the indices

Comment thread src/bases_fixed.jl Outdated
Base.IteratorSize(::Type{<:FixedBasis}) = Base.HasLength()
Base.length(b::FixedBasis) = length(b.elts)
struct SubBasis{T,I,V,B<:AbstractBasis{T,I}} <: FiniteSupportBasis{T,I}
supporting_elts::V

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be the list of indices of the parent_basis. For DiracBasis, since indices are the same as elements, it works as well

@kalmarek

Copy link
Copy Markdown
Collaborator Author

@blegat I was pondering this topic over and over;
I have the feeling that the whole thing should be fixed on the level of coefficients instead of basis. And maybe that's why you should provide a few test applications, so that I can see where's the crux?

At the moment what we have is

  • B -- the parent basis
  • A1, A2 -- subbases of B (listing indices of B) and
  • algebra elements:
    • f1 contains (A1, v1) where v1 is the vector of coefficients wrt A1)
    • f2 contains (A2, v2).

We need to add/multiply f1 and f2, so we

  1. construct c1 a coefficients object from v1 and A1 (i.e. the one that implements nonzero_pairs)
  2. construct c2 for v2 and A2
  3. pass those into our mul!/add! functions
  • inside we need to construct sc::SparseCoefficients containing the result (this will be non-generic code btw. as preallocate in the generic is called only once and the result is stored directly there)
  1. construct A3 -- a subbasis of B from sc and the corresponding vector v3
  2. f3 needs to store now (A3, v3).

It seems that all of this can be achieved on the level of coefficients.
Why can't f1 already contain coefficients with respect to B which internally store (v1, list of corresponding indices of B)?

@blegat

blegat commented Nov 20, 2024

Copy link
Copy Markdown
Member

Good question. I definitely need an ExplicitBasis like SubBasis to represent a basis not necessarily used by an AlgebraElement but maybe we could consider that whenever you create an algebra element, you always use the parent ImplicitBasis. This is actually what I already do in MultivariateBases and SumOfSquares. I do all computation with implicit bases and then I just use explicit basis with coeffs.
The big blocker at the moment is the ability to represent elements from https://github.com/kalmarek/SymbolicWedderburn.jl/
We have a basis b1 of monomials of degree d and a basis b2 of monomials of degree up to 2d.
We do symmetry adapted basis for b1 -> a1 and a symmetry adapted basis for b2 -> a2.
We need to compute coeffs(a2, a1' * Q * a1).
So we should create a basis that concatenates a1 and a2 and have coeffs(a2, a1' * Q * a1) working.
If we can refactor https://github.com/kalmarek/SymbolicWedderburn.jl/blob/master/examples/sos_problem.jl using StarAlgebras then it means I can use that in SumOfSquares. At the moment, symmetry reduction in SumOfSquares has not been updated yet so that's the blocker to release a new version of SumOfSquares. Since in SumOfSquares, everything need to implement the StarAlgebras interface now, I need to implement coeffs(a2, a1' * Q * a1) using StarAlgebras so once we have a StarAlgebras basis for SymbolicWedderburn all lights will be green.
So the crux is https://github.com/kalmarek/SymbolicWedderburn.jl/blob/master/examples/sos_problem.jl / kalmarek/SymbolicWedderburn.jl#78 !

@kalmarek

Copy link
Copy Markdown
Collaborator Author

@blegat, I'm not sure what do you mean by

If we can refactor https://github.com/kalmarek/SymbolicWedderburn.jl/blob/master/examples/sos_problem.jl using StarAlgebras then it means I can use that in SumOfSquares.

Nowhere there do we form a product coeffs(a2, a1'*Q*a1) and that code after small tweaks should work with the newest StarAlgebras.

Here's some newly updated code that make use of DiracBasis and switches to FixedBasis only when particular (fixed) dimension relaxation is required:

import StarAlgebras as SA
let X = .... # AlgebraElement for a StarAlgebra of FPMonoid (infinite dimensional, DiracBasis)
    A = parent(elts)
    unit = one(A)

    # compute somehow a set of elements from `basis(A)` where dual sos-problem for X makes sense.
    linsupp, sizes = linear_supp(X, unit)
    B = SA.FixedBasis(linsupp, SA.mstructure(SA.basis(A)))
    
    # length(word(x)) corresponds to degree of polynomials
    N = maximum(x -> sizes[length(FPMonoids.word(x))÷2], linsupp)
        
    mt = let psd_basis = @view linsupp[1:N] # linsupp is ordered by word-length
        # here we use DiracMStructure of `B` and `mt` is `Matrix{<:Integer}`
        mt = [B[star(x)*y] for x in psd_basis, y in psd_basis]
    end

    model = JuMP.Model()
    # y is a vector of variables in basis `B`!
    y = @variable model y[1:length(B)]
    @objective model Max dot(coeffs(X, B), y) # max dot(X, y)
    @constraint model dot(coeffs(unit, B), y) == 1 # given a normalized `y`
    let P = @view y[mt]
        @constraint model P in PSDCone() # and mt defines a psd matrix
    end

    return model
end

see also https://github.com/kalmarek/QuantumStuff.jl/blob/mk/new_fpmonoids/src/psd_problems.jl

@blegat

blegat commented Nov 26, 2024

Copy link
Copy Markdown
Member

Thanks, I'll play around with while trying to update jump-dev/SumOfSquares.jl#375

@blegat

blegat commented Nov 28, 2024

Copy link
Copy Markdown
Member

Meeting notes:
q is SOS
∃ Q PSD s.t.
q == g -> on some basis zero_basis
where g := gram_basis' * Q * gram_basis
coeffs(zero_basis, gram_basis' * Q * gram_basis)

zero_basis -> Any SA.ExplicitBasis
gram_basis -> Any SA.ExplicitBasis
For all a, b in gram_basis, a*b ∈ zero_basis

coeffs(zero_basis, q) == coeffs(zero_basis, gram_basis' * Q * gram_basis)

How to compute coeffs(zero_basis, gram_basis' * Q * gram_basis) ???

function quadratic_form(Q, basis)
    p = zero(implicit_basis(zero_basis))
    MA.operate!(..., p, gram_basis' * Q * gram_basis)
    return p
end
coeffs(zero_basis, quadratic_form(gram_matrix.Q, gram_matrix.basis))

Symmetry case:
gram_basis Fixed basis containing polynomials or more generally AlgebraElement{FullBasis{B}}
B could be Monomial or B could be Chebyshev

MA.operate!(..., p, gram_basis' * Q * gram_basis)
for row, col
   MA.operate!(...,
       p::AlgebraElement{FullBasis{B}},
       1 * star(gram_basis[row])::SymmetryAdapted{B},
       Q[row, col] * gram_basis[col]::SymmetryAdapted{B},
   )
end
MA.operate!(..., p::AlgebraElement{FullBasis{B}}, ::AlgebraElement{FullBasis{B}})

from SOS

function MA.operate!(
    op::SA.UnsafeAddMul{typeof(*)},
    p::SA.AlgebraElement,
    g::GramMatrix,
    args::Vararg{Any,N},
) where {N}
    for row in eachindex(g.basis)
        row_star = SA.star(g.basis[row])
        for col in eachindex(g.basis)
            MA.operate!(
                op,
                p,
                MB.term_element(g.Q[row, col], identity(algebra(p))),
                MB.convert_basis(row_star, SA.algebra(p)),
                MB.convert_basis(g.basis[col], SA.algebra(p)),
                args...,
            )
        end
    end
    return p
end

Conclusion, we should have something like this in StarAlgebras: operate!(::UnsafeAddMul, ::AlgebraElement, QuadraticForm).

@kalmarek

Copy link
Copy Markdown
Collaborator Author
struct QuadraticForm{T}
    Q::T
end

basis(Q::QuadraticForm) = basis(Q.Q) # ExplicitBasis
Base.getindex(Q, i::T, j::T) where {T} = Q[basis(Q)[i], basis(Q)[j]]

function Base.getindex(Q, i::Integer, j::Integer)
    # returns the q_ij
    return Q[i, j]
end

function MA.operate!(
    op::UnsafeAddMul,
    p::T, # implicit basis
    Q::QuadraticForm,
)
    for b1 in basis(Q)
        b1′ = star(b1)
        for b2 in basis(Q)
            MA.operate!(op, p, (1, b1′), (Q[i, j], b2))
        end
    end
    return p
end

Comment thread src/bases_fixed.jl Outdated
# This file is a part of StarAlgebras.jl. License is MIT: https://github.com/JuliaAlgebra/StarAlgebras.jl/blob/main/LICENSE
# Copyright (c) 2021-2025: Marek Kaluba, Benoît Legat

abstract type FiniteSupportBasis{T,I} <: ExplicitBasis{T,I} end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kalmarek What would be the difference between a FiniteSupportBasis and an ExplicitBasis ? I thought that an ExplicitBasis was a basis with a finite number of elements ^^

@blegat

blegat commented Apr 28, 2025

Copy link
Copy Markdown
Member

@kalmarek It's now ready for your review

@blegat blegat mentioned this pull request Apr 28, 2025
Comment thread test/perm_grp_algebra.jl
Comment thread src/bases_fixed.jl Outdated
Comment thread src/bases.jl
Implicit bases are not stored in memory and can be potentially infinite.
abstract type ImplicitBasis{T,I} <: AbstractBasis{T,I} end

Implicit bases are bases that contains the product of all its elements.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm. in principle this is not guaranteed, but we could make this assumption

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I notice that it didn't have trait in the description that all instances would have which kind of means that this abstract type isn't useful. The way we use it is when multiplying AlgebraElement so this description is kind of the assumption we have. We could say that if the user violates the assumption then it will be fine but AlgebraElement might throw in the multiplication

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm planning to make a PR that tries to bring the concept of implicit_basis corresponding to an explicit one because I need it for SOS

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit like #79

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can revisit then

Comment thread src/bases.jl Outdated
blegat and others added 2 commits April 29, 2025 13:36
Co-authored-by: Marek Kaluba <kalmar@mailbox.org>

@kalmarek kalmarek left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like that most of the changes are clarifications in the docstrings!

We need to take care of #80 though before we could release; I'll have a look at this maybe today in the evening.

@kalmarek

Copy link
Copy Markdown
Collaborator Author

@blegat If your're fine with this feel free to squash and merge.

@kalmarek

Copy link
Copy Markdown
Collaborator Author

(and give yourself a positive review :D)

@blegat

blegat commented Apr 29, 2025

Copy link
Copy Markdown
Member

Yes, we're getting close but we are not ready to release yet

@blegat blegat merged commit 7898009 into main Apr 29, 2025
@blegat blegat deleted the mk/subbasis branch March 27, 2026 07:42
@blegat blegat mentioned this pull request Mar 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants